const path = require("path");
const TerserPlugin = require("terser-webpack-plugin");
const CompressionPlugin = require("compression-webpack-plugin");
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i

const IS_PROD = process.env.NODE_ENV !== "development";

function resolve(dir) {
  return path.join(__dirname, dir);
}

// 配置说明：https://www.cnblogs.com/makalochen/p/13984699.html
const CDN = {
  // 忽略的打包文件
  // 项目部署打包时使用CDN节点的别名方式进行打包，而不用import本地引入。
  // 左边放package.json中的扩展名称，右边放项目依赖的名称（项目初始化要用的名称）
  // 名称中带中横线的需使用引号扩起来
  externals: {
    'vue': "Vue",
    "element-ui": "ELEMENT",
    'x2js': "X2JS",
    "bpmn-js/lib/Modeler": "BpmnJS",
    'vue-router': 'VueRouter',
    'vuex': 'Vuex',
    'axios': 'axios',
  },
  css: [],
  js: [
    //todo 目前政务项目不建议使用cdn，在政务内网无法访问外网的情况下，此方案无解。
    "https://unpkg.com/bpmn-js@8.8.3/dist/bpmn-modeler.production.min.js",
    "https://unpkg.com/x2js@3.4.2/dist/x2js.min.js",
    "https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js",
    "https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.0/index.min.js"
  ]
};

module.exports = {
  publicPath: "/bureauvp/",
  outputDir: "bureauvp",
  // assetsDir: "assets",   //放置生成的静态资源 (js、css、img、fonts)的(相对于 outputDir 的) 目录。
  lintOnSave: false,   //禁止eslint
  productionSourceMap: false,  //去除vue打包后js目录下生成的.map文件，用于加速生产环境构建
  filenameHashing: false, // 打包的时候不使用hash值.因为我们有时间戳来确定项目的唯一性了.
  // CSS 相关选项
  css: {
    // 是否使用css分离插件 ExtractTextPlugin，采用独立样式文件载入，不采用<style>方式内联至html文件中
    // 默认生产环境下是 true，开发环境下是 false。即如果配置production，则变成true
    // todo 目前的代码，如果采用分离css的话，会导致除了首页正常外，其他页面的顶部菜单栏渲染有问题
    extract: false,
    // 是否在构建css样式映射，false将提高构建速度
    sourceMap: false,
    // css预设器配置项
    loaderOptions: {
      css: {},  // 这里的选项会传递给css-loader
      postcss: {} // 这里的选择会传递给psotcss-loader
    }, // css预设器配置项，详见：https://cli.vuejs.org/zh/config/#css-loaderoptions
    // 启用 CSS modules for all css / pre-processor files.
    modules: false
  },
  // 构建时开启多进程处理 babel 编译
  //是否为 Babel 或 TypeScript 使用 thread-loader。
  //该选项在系统的 CPU 有多于一个内核时自动启用，仅作用于生产构建，在适当的时候开启几个子进程去并发的执行压缩
  parallel: require("os").cpus().length > 1,
  chainWebpack: (config) => {
    // https://blog.csdn.net/qq_39025670/article/details/110951945
    // 移除prefetch（预取）插件。意图获取一些资源，已备下一个导航/页面使用
    // config.plugins.delete('prefetch');
    // 移除preload（预载）插件。预先加载资源，但并不执行，只在需要时才执行他
    config.plugins.delete('preload');
    // 定义文件夹的路径
    config.resolve.alias
      .set('@', resolve('src'))
      .set('@a', resolve('src/assets'))
      .set('@c', resolve('src/components'))
      .set('@r', resolve('src/router'))
      .set('@s', resolve('src/store'))
      .set('@v', resolve('src/views'));

    // 压缩图片
    const imagesRule = config.module.rule('images')
    imagesRule.uses.clear()
    imagesRule.use('file-loader')
      .loader('url-loader')
      .options({
        limit: 10240,
        fallback: {
          loader: 'file-loader',
          options: {
            disable: process.env.NODE_ENV === "development",  //开发环境禁止压缩
            outputPath: 'static/images'
          }
        }
      })


    // ============注入cdn start============
    config.plugin("html").tap(args => {
      // 生产环境或本地需要cdn时，才注入cdn
      if (IS_PROD) args[0].cdn = CDN;
      return args;
    });

    config.when(IS_PROD, config => {
      //除去打包中后的console等调试日志信息
      config.optimization.minimizer([new TerserPlugin({
        terserOptions: {
          mangle: true, // 混淆，默认也是开的，mangle也是可以配置很多选项的，具体看后面的链接
          compress: {
            drop_console: true, //传true就是干掉所有的console.*这些函数的调用.
            drop_debugger: true, //干掉那些debugger;
            pure_funcs: ['console.log'] // 如果你要干掉特定的函数比如console.info ，又想删掉后保留其参数中的副作用，那用pure_funcs来处理
          }
        }
      })])

      config.optimization.splitChunks({
        chunks: "all",   // async 异步代码分割模式:只分割出异步引入的模块.  initial 同步代码分割模式：只分割同步引入的模块. all 全部
        minSize: 30000,  //引入的文件大于30kb才进行分割
        minChunks: 1,    //模块至少使用次数
        maxAsyncRequests: 10, //同时加载的模块数量最多是10个，只分割出同时引入的前10个文件
        maxInitialRequests: 3,  //首次加载引入模块可分割的最大值
        automaticNameDelimiter: "~", //：缓存组名称和生成文件名称之间的连接字符串
        cacheGroups: {  //缓存组，将所有加载模块放在缓存里面一起分割打包
          libs: {
            name: "chunk-libs",
            test: /[\\/]node_modules[\\/]/,
            priority: 10,
            chunks: "initial", // only package third parties that are initially dependent
          },
          elementUI: {
            name: "chunk-element-ui", // split elementUI into a single package
            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
            test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
          },
          commons: {
            name: "chunk-components",
            test: resolve("components"), // can customize your rules
            minChunks: 1, //  minimum common number
            priority: 5,
            reuseExistingChunk: true,
          },
          default: {
            priority: 0,
            reuseExistingChunk: true, //模块嵌入引入时，判断是否复用已经被打包的模块
          }
        }
      });
      config.optimization.runtimeChunk("single");
    });

    const entry = config.entry('app');
    entry
      .add('babel-polyfill')
      .end();
    entry
      .add('classlist-polyfill')
      .end();
    entry
      .add('@/mock')
      .end();
  },
  configureWebpack: (config) => {
    config.externals = CDN.externals;
    if (IS_PROD) {
      config.plugins.push(
        new CompressionPlugin({
          algorithm: 'gzip', //使用gzip压缩
          test: productionGzipExtensions, //匹配文件名
          minRatio: 1, //压缩率小于1才会压缩
          threshold: 10240, //对超过10k的数据压缩
          cache: true,
          deleteOriginalAssets: false, //是否删除未压缩的源文件，谨慎设置，如果希望提供非gzip的资源，可不设置
        })
      );
    }
  },
  devServer: {
    // 端口配置
    port: 1888,
    disableHostCheck: true,
    // 反向代理配置
    // proxy: {
    //   '/api': {
    //     target: 'http://localhost:9900',
    //     ws: true,
    //     pathRewrite: {
    //       '^/api': '/'
    //     }
    //   }
    // }
  }
}
